/*
 * @(#)XfslLog.java        2003/01/01
 *
 * This file is part of Xfuzzy 3.0, a design environment for fuzzy logic
 * based systems.
 *
 * (c) 2000 IMSE-CNM. The authors may be contacted by the email address:
 *                    xfuzzy-team@imse.cnm.es
 *
 * Xfuzzy is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * Xfuzzy is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */


package xfuzzy.xfsl.model;

import java.io.*;
import java.util.*;

/**
 * Almacenamiento del proceso de aprendizaje en un fichero de log
 * 
 * @author Francisco Jos� moreno Velo
 *
 */
public class XfslLog implements Cloneable {

	//----------------------------------------------------------------------------//
	//                            MIEMBROS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Fichero de log
	 */
	private File file;
	
	/**
	 * Selecci�n de variables a almacenar
	 */
	private boolean log[];
	
	/**
	 * Flag para indicar si se trata de un problema de clasificaci�n
	 */
	private boolean classif;
	
	/**
	 * Flujo de salida del fichero
	 */
	private FileOutputStream stream;
	
	/**
	 * Car�cter de fin de l�nea (depende del S.O.)
	 */
	private String eol = System.getProperty("line.separator", "\n");

	//----------------------------------------------------------------------------//
	//                                CONSTRUCTOR                                 //
	//----------------------------------------------------------------------------//

	/**
	 * Constructor por defecto
	 */
	public XfslLog() {
		this.file = null;
		this.log =  new boolean[9];
		for(int i=0; i<log.length; i++) log[i] = true;
		this.classif = false;
		this.stream = null;
	}

	/**
	 * Constructor usado en la configuraci�n
	 */
	public XfslLog(File file,Vector<String> v) {
		this.file = file;
		this.log = new boolean[9];
		boolean base = (v.size() == 0);
		for(int i=0; i<log.length; i++) log[i] = base;
		for(int i=0; i<v.size(); i++) parse(v.elementAt(i));
		this.classif = false;
		this.stream = null;
	}

	//----------------------------------------------------------------------------//
	//                             M�TODOS P�BLICOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Duplica el objeto
	 */
	public Object clone() {
		XfslLog clone = new XfslLog();
		clone.setFile(this.file);
		clone.setSelection(this.log);
		clone.setClassif(this.classif);
		return clone;
	}

	/**
	 * Estudia si se ha seleccionado la opci�n de log
	 */
	public boolean isOn() {
		return (this.file != null);
	}

	/**
	 * Devuelve el fichero seleccionado para almacenar la historia
	 */
	public File getFile() {
		return this.file;
	}

	/**
	 * Selecciona el fichero para almacenar la historia
	 */
	public void setFile(File file) {
		if(file == null) this.file = null;
		else this.file = new File(file.getAbsolutePath());
	}

	/**
	 * Devuelve la selecci�n de variables a almacenar
	 */
	public boolean[] getSelection() {
		return this.log;
	}

	/**
	 * Establece la selecci�n de variables a almacenar
	 */
	public void setSelection(boolean[] sel) {
		for(int i=0; i<sel.length && i<log.length; i++) log[i] = sel[i];
	}

	/**
	 * Analiza si el almacenamiento corresponde a un clasificador
	 */
	public boolean getClassif() {
		return this.classif;
	}

	/**
	 * Selecciona si es un almacenamiento de un clasificador
	 */
	public void setClassif(boolean classif) {
		this.classif = classif;
	}

	/**
	 * Representaci�n que se muestra en la ventana
	 */
	public String toString() {
		if(file == null) return "";
		String code = "";
		if(log[0]) code += ", iter";
		if(log[1]) code += ", trn_error";
		if(log[2] && !classif) code += ", trn_rmse";
		if(log[2] && classif) code += ", trn_rate";
		if(log[3] && !classif) code += ", trn_mxae";
		if(log[3] && classif) code += ", trn_count";
		if(log[4]) code += ", trn_var";
		if(log[5]) code += ", tst_error";
		if(log[6] && !classif) code += ", tst_rmse";
		if(log[6] && classif) code += ", tst_rate";
		if(log[7] && !classif) code += ", tst_mxae";
		if(log[7] && classif) code += ", tst_count";
		if(log[8]) code += ", tst_var";
		if(code.length()>0) code = code.substring(2);
		return file.getName()+" ("+code+")";
	}

	/**
	 * Representaci�n en formato XML
	 */
	public String toXML() {
		String code = "\t\t<log file=\""+file.getAbsolutePath()+"\">"+eol;
		if(log[0]) code += "\t\t\t<var name=\"iter\"></var>"+eol;
		if(log[1]) code += "\t\t\t<var name=\"trn_error\"></var>"+eol;
		if(log[2] && !classif) code += "\t\t\t<var name=\"trn_rmse\"></var>"+eol;
		if(log[2] && classif) code += "\t\t\t<var name=\"trn_rate\"></var>"+eol;
		if(log[3] && !classif) code += "\t\t\t<var name=\"trn_mxae\"></var>"+eol;
		if(log[3] && classif) code += "\t\t\t<var name=\"trn_count\"></var>"+eol;
		if(log[4]) code += "\t\t\t<var name=\"trn_var\"></var>"+eol;
		if(log[5]) code += "\t\t\t<var name=\"tst_error\"></var>"+eol;
		if(log[6] && !classif) code += "\t\t\t<var name=\"tst_rmse\"></var>"+eol;
		if(log[6] && classif) code += "\t\t\t<var name=\"tst_rate\"></var>"+eol;
		if(log[7] && !classif) code += "\t\t\t<var name=\"tst_mxae\"></var>"+eol;
		if(log[7] && classif) code += "\t\t\t<var name=\"tst_count\"></var>"+eol;
		if(log[8]) code += "\t\t\t<var name=\"tst_var\"></var>"+eol;
		code += "\t\t</log>"+eol;
		return code;
	}
	
	/**
	 * Abre el fichero y escribe la cabecera
	 */
	public void open() {
		if(file == null) return;
		try {
			stream = new FileOutputStream(file);
			String header = "# "+toString()+eol+eol;
			stream.write(header.getBytes());
		} catch(Exception ex) { System.out.println(""+ex); }
	}

	/**
	 * Cierra el fichero
	 */
	public void close() {
		if(file == null) return;
		if(stream == null) return;
		try { stream.close(); stream = null; } catch(Exception ex) {}
	}

	/**
	 * Almacena el resultado de una iteraci�n del aprendizaje
	 */
	public void write(XfslStatus status) {
		if(file == null) return;
		String line = "";
		if(log[0]) line += status.epoch+" ";
		if(log[1]) line += status.trn.error+" ";
		if(log[2]) line += status.trn.rmse+" ";
		if(log[3]) line += status.trn.mxae+" ";
		if(log[4]) line += status.trn.var+" ";
		if(log[5]) line += status.tst.error+" ";
		if(log[6]) line += status.tst.rmse+" ";
		if(log[7]) line += status.tst.mxae+" ";
		if(log[8]) line += status.tst.var+" ";
		line += eol;
		if(stream == null) open();
		try { stream.write(line.getBytes()); } catch(Exception ex) {}
	}

	//----------------------------------------------------------------------------//
	//                             M�TODOS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Selecciona una variable de estado a almacenar
	 */
	private void parse(String var) {
		if(var.trim().equals("iter")) log[0] = true;
		if(var.trim().equals("trn_error")) log[1] = true;
		if(var.trim().equals("trn_rmse")) log[2] = true;
		if(var.trim().equals("trn_rate")) log[2] = true;
		if(var.trim().equals("trn_mxae")) log[3] = true;
		if(var.trim().equals("trn_count")) log[3] = true;
		if(var.trim().equals("trn_var")) log[4] = true;
		if(var.trim().equals("tst_error")) log[5] = true;
		if(var.trim().equals("tst_rmse")) log[6] = true;
		if(var.trim().equals("tst_rate")) log[6] = true;
		if(var.trim().equals("tst_mxae")) log[7] = true;
		if(var.trim().equals("tst_count")) log[7] = true;
		if(var.trim().equals("tst_var")) log[8] = true;
	}
}
